package com.joven.product.service.infrastructure.repository.impl;

import com.baomidou.mybatisplus.extension.service.IService;
import com.joven.product.service.business.domain.model.entity.BaseDomainObj;
import com.joven.product.service.business.domain.model.entity.id.DomainObjId;
import com.joven.product.service.business.domain.model.entity.id.EntityStatus;
import com.joven.product.service.infrastructure.converter.BaseConverter;
import com.joven.product.service.infrastructure.persistence.db.entity.BaseDataObj;
import com.joven.product.service.infrastructure.repository.BaseRepository;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class BaseRepositoryImpl<T extends DomainObjId, DomainObj extends BaseDomainObj<T>, DataObj extends BaseDataObj> implements BaseRepository<T, DomainObj, DataObj> {
    private final IService<DataObj> dao;
    private final BaseConverter<T, DomainObj, DataObj> converter;

    public BaseRepositoryImpl(IService<DataObj> dao, BaseConverter<T, DomainObj, DataObj> converter) {
        this.dao = dao;
        this.converter = converter;
    }

    public IService<DataObj> getDao() {
        return dao;
    }

    @Override
    public boolean save(DomainObj data) {
        if (data == null) {
            return false;
        }
        DataObj dataObj = converter.toDataObj(data);
        if (data.getId().getStatus().equals(EntityStatus.NEW)) {
            dao.save(dataObj);
            data.getId().setValue(dataObj.getId());
        } else if (data.getId().getStatus().equals(EntityStatus.CHANGED)) {
            return dao.updateById(dataObj);
        } else if (data.getId().getStatus().equals(EntityStatus.DELETED)) {
            return dao.removeById(dataObj.getId());
        }
        return true;
    }

    @Override
    public boolean saveBatch(List<DomainObj> datas) {
        if (CollectionUtils.isEmpty(datas)) {
            return false;
        }
        Map<EntityStatus, List<DomainObj>> group = datas.stream().collect(Collectors.groupingBy(it -> it.getId().getStatus()));
        List<DomainObj> datas2Add = group.get(EntityStatus.NEW);
        List<DomainObj> datas2Update = group.get(EntityStatus.CHANGED);
        List<DomainObj> datas2Delete = group.get(EntityStatus.DELETED);
        List<DataObj> entityList = converter.toDataObjs(datas2Add);
        if (ObjectUtils.isNotEmpty(datas2Delete)) {
            dao.removeByIds(datas2Delete.stream().map(it -> it.getId().getValue()).collect(Collectors.toList()));
        }
        if (CollectionUtils.isNotEmpty(entityList)) {
            dao.saveBatch(entityList);
            Map<String, Long> map = entityList.stream().collect(Collectors.toMap(DataObj::getPreId, DataObj::getId));
            datas2Add.forEach(it -> it.getId().setValue(map.get(it.getId().getPreId())));
        }
        dao.updateBatchById(converter.toDataObjs(datas2Update));
        return true;
    }
}